#include "stdafx.h"
#include "CppUnitTest.h"
#include <HSModel/Model3D.h>
#include <HSModel/KDTree.h>
#include <HSModel/GeometryUtils.h>
#include <HSModel/World.h>
#include <HSModel/Landscape.h>

#include "HSModel/Ground.h"
#include <HSModel/SharedConstants.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace HSModelTests
{

	TEST_CLASS(KDTreeTests)
	{
	public:
		
		TEST_METHOD(TreePicksOneTriangle)
		{
		Model3D model;
		Point3DID point1 = model.AddPoint(1, 1, 0);
		Point3DID point2 = model.AddPoint(1, 4, 0);
		Point3DID point3 = model.AddPoint(4, 1, 0);
		model.AddTriangle(point1, point2, point3);
		
		TVector3 origin = TVector3(2, 2, 2);
    TVector3 direction = TVector3(0, 0, 1);
    TLine3 line = TLine3(origin, direction);

		KDTree tree (model.Triangles().begin(), model.Triangles().end());

		auto triangles = tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() > 0);
		Assert::IsTrue(triangles[0]->GetPoint(0) == TVector3(1, 1, 0));
		Assert::IsTrue(triangles[0]->GetPoint(1) == TVector3(1, 4, 0));
		Assert::IsTrue(triangles[0]->GetPoint(2) == TVector3(4, 1, 0));
		}

		TEST_METHOD(TreePicksTwoTriangles)
		{
		Model3D model;
		Point3DID point1 = model.AddPoint(1, 1, 0);
		Point3DID point2 = model.AddPoint(4, 1, 0);
		Point3DID point3 = model.AddPoint(1, 4, 1);
		Point3DID point4 = model.AddPoint(1, 1, 2);
		Point3DID point5 = model.AddPoint(4, 1, 2);

		model.AddTriangle(point1, point2, point3);
		model.AddTriangle(point3, point4, point5);
		
		TVector3 origin = TVector3(2, 2, 5);
    TVector3 direction = TVector3(0, 0, 1);
    TLine3 line = TLine3(origin, direction);

		KDTree tree (model.Triangles().begin(), model.Triangles().end());

		auto triangles = tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() >= 2);
		}

		TEST_METHOD(PickTwoTrianglesFromCube)
		{
		Model3D model;
		Point3DID point1 = model.AddPoint(1, 1, 1);
		Point3DID point2 = model.AddPoint(6, 1, 1);
		Point3DID point3 = model.AddPoint(1, 6, 1);
		Point3DID point4 = model.AddPoint(6, 6, 1);
		Point3DID point5 = model.AddPoint(1, 1, 6);
		Point3DID point6 = model.AddPoint(6, 1, 6);
		Point3DID point7 = model.AddPoint(1, 6, 6);
		Point3DID point8 = model.AddPoint(6, 6, 6);

		model.AddTriangle(point1, point2, point4);
		model.AddTriangle(point1, point3, point4);
		model.AddTriangle(point2, point4, point6);
		model.AddTriangle(point4, point6, point8);
		model.AddTriangle(point1, point3, point7);
		model.AddTriangle(point1, point5, point7);
		model.AddTriangle(point5, point6, point7);
		model.AddTriangle(point6, point7, point8);
		model.AddTriangle(point3, point4, point7);
		model.AddTriangle(point4, point7, point8);
		model.AddTriangle(point1, point5, point6);
		model.AddTriangle(point1, point2, point6);

		// created and added a cube to model3D

		
		TVector3 origin = TVector3(3, 2, -1);
    TVector3 direction = TVector3(0, 0, 1);
    TLine3 line = TLine3(origin, direction);

		KDTree tree (model.Triangles().begin(), model.Triangles().end());

		auto triangles = tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() >= 2);
		}

		TEST_METHOD(PickTrianglesFromGround)
		{
    HeightMap height_map = HeightMap(GroundConstants::CELL_COUNT + 1, GroundConstants::CELL_COUNT + 1);
    GeneratedHeightMapWithDiamondSquare(height_map, GroundConstants::PLAINS_PERCENTAGE, GroundConstants::MAX_HEIGHT);
    Ground ground(height_map, GroundConstants::CELL_SIZE, GroundConstants::WATER_LEVEL);
		auto& model = ground.GetLandscape().GetModel();

    KDTree test_tree(model.Triangles().begin(), model.Triangles().end());
		
		TVector3 origin = TVector3(32.3775, 161.182, 376.122);
		TVector3 direction = TVector3(0.677026, -0.524568, -0.516201);
		TLine3 line = TLine3(origin, direction);
		try 
			{
			auto triangles = test_tree.PickTriangles(line);
			}
		catch(...)
			{
			Assert::IsTrue(1 == 100022);
			}
		Assert::IsTrue(1 == 1);
		}

		TEST_METHOD(PickTrianglesFromGround1)
		{
    HeightMap height_map = HeightMap(GroundConstants::CELL_COUNT + 1, GroundConstants::CELL_COUNT + 1);
    GeneratedHeightMapWithDiamondSquare(height_map, GroundConstants::PLAINS_PERCENTAGE, GroundConstants::MAX_HEIGHT);
    Ground ground(height_map, GroundConstants::CELL_SIZE, GroundConstants::WATER_LEVEL);
		auto& model = ground.GetLandscape().GetModel();
		KDTree test_tree(model.Triangles().begin(), model.Triangles().end());
		
		TVector3 origin = TVector3(227.726, 304.355, 156.246);
		TVector3 direction = TVector3(-0.49937, -0.442869, -0.744645);
		TLine3 line = TLine3(origin, direction);
		auto triangles = test_tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() > 0);
		}

		TEST_METHOD(PickTrianglesFromHole)
		{
    HeightMap height_map = HeightMap(5, 5);
    GeneratedHeightMapWithDiamondSquare(height_map, 0.5, 10);
    Ground ground(height_map, 10, -10);
		auto& model = ground.GetLandscape().GetModel();
		KDTree test_tree(model.Triangles().begin(), model.Triangles().end());
		
		TVector3 origin = TVector3(-33.28, -38.0585, 155.282);
		TVector3 direction = TVector3(0.186259, 0.292658, -0.937901);
		TLine3 line = TLine3(origin, direction);
		
		auto triangles = test_tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() > 0);
		}

		TEST_METHOD(TreePicksOneTriangleWithNegativeCoordinates)
		{
		Model3D model;
		Point3DID point1 = model.AddPoint(-1, -1, -1);
		Point3DID point2 = model.AddPoint(-1, -1, -4);
		Point3DID point3 = model.AddPoint(-4, -1, -1);
		model.AddTriangle(point1, point2, point3);
		
		TVector3 origin = TVector3(-2, -2, -2);
    TVector3 direction = TVector3(0, 1, 0);
    TLine3 line = TLine3(origin, direction);

		KDTree tree (model.Triangles().begin(), model.Triangles().end());

		auto triangles = tree.PickTriangles(line);
		Assert::IsTrue(triangles.size() > 0);
		}
	};
}